using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using WalkingTec.Mvvm.Core;
using HengTong.Model.Db.Hr.Attendance.Rule;

namespace HengTong.Model.Db.Hr.Attendance
{
    /// <summary>
    /// 考勤班次实体类，用于定义考勤班次规则及相关设置
    /// </summary>
    /// <remarks>
    /// 包含班次基本信息、上下班时间设置、打卡有效窗口、违规规则、
    /// 晚走晚到规则和工时折算等完整的考勤管理功能
    /// </remarks>
    public class SysAttendanceShift : TopBasePoco
    {
        /// <summary>
        /// 获取或设置班次规则名称
        /// </summary>
        /// <value>班次规则的显示名称，用于标识不同的考勤班次</value>
        [Display(Name = "班次名称", Description = "考勤班次规则的显示名称", GroupName = "基本信息")]
        [Required(ErrorMessage = "班次名称不能为空")]
        [MaxLength(128, ErrorMessage = "班次名称长度不能超过128个字符")]
        public string Name { get; set; }

        /// <summary>
        /// 获取或设置班次显示颜色标识
        /// </summary>
        /// <value>用于在界面上区分不同班次的颜色代码（如：#FF0000）</value>
        [Display(Name = "显示颜色", Description = "为当前班次标记颜色，便于在排班表中能快速区分不同班次", GroupName = "基本信息")]
        [MaxLength(64, ErrorMessage = "颜色标识长度不能超过64个字符")]
        public string DisplayColor { get; set; }

        /// <summary>
        /// 获取或设置班次标签类型
        /// </summary>
        /// <value>班次的分类标签：A、中班或夜班</value>
        [Display(Name = "班次标签", Description = "班次类型标签（A/中班/B）", GroupName = "基本信息")]
        public SysAttendanceShiftTag? Tag { get; set; }

        /// <summary>
        /// 获取或设置班次是否启用
        /// </summary>
        /// <value>true表示启用，false表示禁用</value>
        [Display(Name = "是否启用", Description = "班次规则是否生效", GroupName = "基本信息")]
        public bool IsEnabled { get; set; } = true;

        /// <summary>
        /// 获取或设置班次备注信息
        /// </summary>
        /// <value>对班次规则的详细说明或特殊要求</value>
        [Display(Name = "备注", Description = "班次规则的备注信息", GroupName = "基本信息")]
        [MaxLength(512, ErrorMessage = "备注长度不能超过512个字符")]
        public string Remark { get; set; }

        // —— 上下班时间与打卡有效窗口 ——
        // 在上、下班卡有效时间区间内的打卡将被视为有效打卡

        /// <summary>
        /// 获取或设置上班时间的基准日期偏移
        /// </summary>
        /// <value>相对于考勤日期的偏移：前一日、当日或次日</value>
        [Display(Name = "上班基准日", Description = "上班时间相对于考勤日期的偏移", GroupName = "上班时间")]
        public SysDayOffset WorkStartDayOffset { get; set; } = SysDayOffset.当日;

        /// <summary>
        /// 获取或设置标准上班时间
        /// </summary>
        /// <value>班次规定的标准上班时间点</value>
        [Display(Name = "上班时间", Description = "班次规定的标准上班时间", GroupName = "上班时间")]
        [DataType(DataType.Time)]
        public TimeSpan WorkStartTime { get; set; } = new TimeSpan(8, 0, 0); // 08:00:00

        /// <summary>
        /// 获取或设置上班打卡有效开始时间的基准日期偏移
        /// </summary>
        /// <value>上班打卡有效窗口开始时间的日期偏移</value>
        [Display(Name = "上班卡有效开始基准日", Description = "上班打卡有效窗口开始时间的日期偏移", GroupName = "上班时间")]
        public SysDayOffset WorkStartPunchStartDayOffset { get; set; } = SysDayOffset.当日;

        /// <summary>
        /// 获取或设置上班打卡有效窗口开始时间
        /// </summary>
        /// <value>允许上班打卡的最早时间点</value>
        [Display(Name = "上班卡有效开始时间", Description = "允许上班打卡的最早时间", GroupName = "上班时间")]
        [DataType(DataType.Time)]
        public TimeSpan WorkStartPunchStartTime { get; set; } = new TimeSpan(7, 0, 0); // 07:00:00

        /// <summary>
        /// 获取或设置上班打卡有效结束时间的基准日期偏移
        /// </summary>
        /// <value>上班打卡有效窗口结束时间的日期偏移</value>
        [Display(Name = "上班卡有效结束基准日", Description = "上班打卡有效窗口结束时间的日期偏移", GroupName = "上班时间")]
        public SysDayOffset WorkStartPunchEndDayOffset { get; set; } = SysDayOffset.当日;

        /// <summary>
        /// 获取或设置上班打卡有效窗口结束时间
        /// </summary>
        /// <value>允许上班打卡的最晚时间点</value>
        [Display(Name = "上班卡有效结束时间", Description = "允许上班打卡的最晚时间", GroupName = "上班时间")]
        [DataType(DataType.Time)]
        public TimeSpan WorkStartPunchEndTime { get; set; } = new TimeSpan(9, 59, 0); // 09:59:00

        /// <summary>
        /// 获取或设置下班时间的基准日期偏移
        /// </summary>
        /// <value>相对于考勤日期的偏移：前一日、当日或次日</value>
        [Display(Name = "下班基准日", Description = "下班时间相对于考勤日期的偏移", GroupName = "下班时间")]
        public SysDayOffset WorkEndDayOffset { get; set; } = SysDayOffset.当日;

        /// <summary>
        /// 获取或设置标准下班时间
        /// </summary>
        /// <value>班次规定的标准下班时间点</value>
        [Display(Name = "下班时间", Description = "班次规定的标准下班时间", GroupName = "下班时间")]
        [DataType(DataType.Time)]
        public TimeSpan WorkEndTime { get; set; } = new TimeSpan(17, 30, 0); // 17:30:00

        /// <summary>
        /// 获取或设置下班打卡有效开始时间的基准日期偏移
        /// </summary>
        /// <value>下班打卡有效窗口开始时间的日期偏移</value>
        [Display(Name = "下班卡有效开始基准日", Description = "下班打卡有效窗口开始时间的日期偏移", GroupName = "下班时间")]
        public SysDayOffset WorkEndPunchStartDayOffset { get; set; } = SysDayOffset.当日;

        /// <summary>
        /// 获取或设置下班打卡有效窗口开始时间
        /// </summary>
        /// <value>允许下班打卡的最早时间点</value>
        [Display(Name = "下班卡有效开始时间", Description = "允许下班打卡的最早时间", GroupName = "下班时间")]
        [DataType(DataType.Time)]
        public TimeSpan WorkEndPunchStartTime { get; set; } = new TimeSpan(15, 29, 0); // 15:29:00

        /// <summary>
        /// 获取或设置下班打卡有效结束时间的基准日期偏移
        /// </summary>
        /// <value>下班打卡有效窗口结束时间的日期偏移</value>
        [Display(Name = "下班卡有效结束基准日", Description = "下班打卡有效窗口结束时间的日期偏移", GroupName = "下班时间")]
        public SysDayOffset WorkEndPunchEndDayOffset { get; set; } = SysDayOffset.当日;

        /// <summary>
        /// 获取或设置下班打卡有效窗口结束时间
        /// </summary>
        /// <value>允许下班打卡的最晚时间点</value>
        [Display(Name = "下班卡有效结束时间", Description = "允许下班打卡的最晚时间", GroupName = "下班时间")]
        [DataType(DataType.Time)]
        public TimeSpan WorkEndPunchEndTime { get; set; } = new TimeSpan(18, 30, 0); // 18:30:00

        // —— 迟到/早退/旷工规则 ——

        /// <summary>
        /// 获取或设置是否启用考勤违规规则
        /// </summary>
        /// <value>true表示启用迟到早退旷工规则，false表示不启用</value>
        [Display(Name = "启用违规规则", Description = "是否启用迟到、早退、旷工等违规规则", GroupName = "违规规则")]
        public bool AttendanceViolationRuleEnabled { get; set; } = true;

        /// <summary>
        /// 获取或设置迟到判定阈值
        /// </summary>
        /// <value>超过标准上班时间多少分钟算作迟到</value>
        [Display(Name = "迟到阈值(分钟)", Description = "超过标准上班时间多少分钟算作迟到", GroupName = "违规规则")]
        [Range(0, 1440, ErrorMessage = "迟到阈值必须在0-1440分钟之间")]
        public int LateMinutesThreshold { get; set; } = 10;

        /// <summary>
        /// 获取或设置早退判定阈值
        /// </summary>
        /// <value>早于标准下班时间多少分钟算作早退</value>
        [Display(Name = "早退阈值(分钟)", Description = "早于标准下班时间多少分钟算作早退", GroupName = "违规规则")]
        [Range(0, 1440, ErrorMessage = "早退阈值必须在0-1440分钟之间")]
        public int EarlyLeaveMinutesThreshold { get; set; } = 1;

        /// <summary>
        /// 获取或设置迟到记旷工阈值
        /// </summary>
        /// <value>迟到超过多少分钟记为旷工</value>
        [Display(Name = "迟到记旷工阈值(分钟)", Description = "迟到超过多少分钟记为旷工", GroupName = "违规规则")]
        [Range(0, 1440, ErrorMessage = "迟到记旷工阈值必须在0-1440分钟之间")]
        public int AbsenceByLateMinutesThreshold { get; set; } = 120;

        /// <summary>
        /// 获取或设置早退记旷工阈值
        /// </summary>
        /// <value>早退超过多少分钟记为旷工</value>
        [Display(Name = "早退记旷工阈值(分钟)", Description = "早退超过多少分钟记为旷工", GroupName = "违规规则")]
        [Range(0, 1440, ErrorMessage = "早退记旷工阈值必须在0-1440分钟之间")]
        public int AbsenceByEarlyLeaveMinutesThreshold { get; set; } = 120;

        /// <summary>
        /// 获取或设置合计偏差记旷工阈值
        /// </summary>
        /// <value>迟到和早退时间合计超过多少分钟记为旷工</value>
        [Display(Name = "合计偏差记旷工阈值(分钟)", Description = "迟到和早退时间合计超过多少分钟记为旷工", GroupName = "违规规则")]
        [Range(0, 1440, ErrorMessage = "合计偏差记旷工阈值必须在0-1440分钟之间")]
        public int AbsenceByTotalDeviationMinutesThreshold { get; set; } = 120;

        // —— 工时折算 ——

        /// <summary>
        /// 获取或设置标准工作时长
        /// </summary>
        /// <value>班次的标准工作时长，单位为分钟</value>
        [Display(Name = "标准工作时长(分钟)", Description = "班次的标准工作时长", GroupName = "工时折算")]
        [Range(0, 100000, ErrorMessage = "标准工作时长必须在0-100000分钟之间")]
        public int StandardWorkMinutes { get; set; } = 570; // 9小时30分钟

        /// <summary>
        /// 获取或设置工时折算出勤天数
        /// </summary>
        /// <value>完成标准工时对应的出勤天数，用于计算出勤率</value>
        [Display(Name = "折算出勤天数", Description = "完成标准工时对应的出勤天数", GroupName = "工时折算")]
        [Range(typeof(decimal), "0", "1000", ErrorMessage = "折算出勤天数必须在0-1000之间")]
        [Column(TypeName = "decimal(4,2)")]
        public decimal AttendanceDays { get; set; } = 1m;

        // —— 补贴规则 ——

        /// <summary>
        /// 获取或设置是否启用补贴规则
        /// </summary>
        /// <value>true表示启用补贴规则，false表示不启用</value>
        [Display(Name = "启用补贴规则", Description = "是否启用该班次的补贴规则计算", GroupName = "补贴规则")]
        public bool SubsidyRuleEnabled { get; set; } = false;

        /// <summary>
        /// 获取或设置班次关联的补贴规则列表
        /// </summary>
        /// <value>该班次适用的所有补贴规则</value>
        [Display(Name = "补贴规则列表", Description = "该班次适用的补贴规则", GroupName = "补贴规则")]
        public List<SysAttendanceSubsidyRule> SubsidyRules { get; set; }

        // —— 排班规则 ——

        /// <summary>
        /// 获取或设置是否在假日安排排班
        /// </summary>
        /// <value>true表示假日也需要排班，false表示假日不排班</value>
        [Display(Name = "假日是否排班", Description = "是否在节假日安排此班次的排班", GroupName = "排班规则")]
        public bool IsHolidayScheduled { get; set; } = false;

        /// <summary>
        /// 获取或设置工作日设置
        /// </summary>
        /// <value>选中的工作日JSON字符串，用于确定哪些天需要上班（周一、周二、周三、周四、周五、周六、周日）</value>
        [Display(Name = "工作日设置", Description = "选择此班次适用的工作日（周一至周日），以JSON格式存储", GroupName = "排班规则")]
        [MaxLength(500, ErrorMessage = "工作日设置长度不能超过500个字符")]
        public string WorkDays { get; set; } = "[\"周一\",\"周二\",\"周三\",\"周四\",\"周五\"]";

        /// <summary>
        /// 获取或设置是否为默认班次
        /// </summary>
        [Display(Name = "是否默认班次", Description = "是否为系统的默认班次，默认班次在排班时优先选择", GroupName = "基本信息")]
        public bool IsDefault { get; set; }

        [Display(Name = "排序")]
        [Column(TypeName = "decimal(4,2)")]
        [Range(0, 99.99, ErrorMessage = "排序值必须在0到99.99之间")]
        [DisplayFormat(DataFormatString = "{0:0.##}")]
        public decimal? Order { get; set; } = 0;
    }

    /// <summary>
    /// 班次标签枚举
    /// </summary>
    /// <remarks>
    /// 用于标识不同时段的班次类型
    /// </remarks>
    public enum SysAttendanceShiftTag
    {
        /// <summary>
        /// A（日间班次）
        /// </summary>
        A = 0,

        /// <summary>
        /// B（夜间班次）
        /// </summary>
        B = 2,

        C = 4,

        D = 6,
        
        休 = 8,
        
        休1 = 10,
        
        休2 = 12
    }

    /// <summary>
    /// 考勤班次日期偏移枚举
    /// </summary>
    /// <remarks>
    /// 用于表示时间相对于考勤基准日期的偏移量，
    /// 主要用于跨日班次的时间计算
    /// </remarks>
    public enum SysDayOffset
    {
        /// <summary>
        /// 前一日（-1天）
        /// </summary>
        上一日 = -1,

        /// <summary>
        /// 当日（0天偏移）
        /// </summary>
        当日 = 0,

        /// <summary>
        /// 次日（+1天）
        /// </summary>
        下一日 = 1
    }
}